-module(katzenreis_callbacks).
-export([add_custom_text_renderer/1,
  get_custom_filter/1, get_custom_tag/1, get_custom_text_renderers/0, init/0,
  set_custom_filter/2, set_custom_tag/3]).

-include("katzenreis.hrl").


%% @doc Initializes the template engine.
%%  Creates new ets tables that include callbacks for custom filters and tags.
%%  This function must be called once before parsing templates.
%% @spec () -> no_return()
%% @since #since

init() ->
  ets:new(?TABLE, [set, named_table]),
  ets:new(?CUSTOM_FILTER_TABLE, [set, named_table]),
  ets:new(?CUSTOM_TAG_TABLE, [set, named_table]).


%% @doc Returns the custom filter callback named `Name',
%%  or `undefined' if no such callback is registered.
%% @spec (filter_name()) -> func_info() | undefined
%% @see set_custom_filter/2
%% @see filter()
%% @since #since

-spec get_custom_filter(filter_name()) -> func_info() | undefined.

get_custom_filter(Name) ->
  case ets:lookup(?CUSTOM_FILTER_TABLE, Name) of
    [{Name, Filter}|_] -> Filter;
    [] -> undefined
  end.


%% @doc Registers a custom filter callback with name.
%% @spec (filter_name(), func_info()) -> no_return()
%% @see get_custom_filter/1
%% @see filter()
%% @since #since

-spec set_custom_filter(filter_name(), func_info()) -> no_return().

set_custom_filter(Name, Fun) ->
  ets:insert(?CUSTOM_FILTER_TABLE, {Name, Fun}).


%% @doc Returns the custom tag callbacks named `Name',
%%  or `undefined' if no such callbacks are registered.
%% @spec (tag_name()) -> {Parser::func_info(), Renderer::func_info()} |
%%  undefined
%% @see set_custom_tag/3
%% @see tag_parser()
%% @see tag_renderer()
%% @since #since

-spec get_custom_tag(tag_name()) ->
  {func_info(), func_info()} | undefined.

get_custom_tag(Name) ->
  case ets:lookup(?CUSTOM_TAG_TABLE, Name) of
    [{Name, Parser, Renderer}|_] -> {Parser, Renderer};
    [] -> undefined
  end.


%% @doc Registers custom tag callbacks with name.
%%  The callbacks are a parsing callback to parse template nodes
%%  used by the custom tag and a rendering callback to render the parsed
%%  template nodes.
%% @spec (tag_name(), Parser::func_info(), Renderer::func_info()) -> no_return()
%% @see get_custom_tag/1
%% @see tag_parser()
%% @see tag_renderer()
%% @since #since

-spec set_custom_tag(tag_name(), func_info(), func_info()) -> no_return().

set_custom_tag(Name, Parser, Renderer) ->
  ets:insert(?CUSTOM_TAG_TABLE, {Name, Parser, Renderer}).


%% @type text_to_render() = string() | {string(), attributes()}.
%%  Text to render.
%% @see text_renderer()
%% @see get_custom_text_renderers/0
%% @see add_custom_text_renderer/1
%%
%% @type text_renderer() = function((string(), attributes(),
%%  context(), options()) -> string()).
%%  Text renderer callback.
%% @see text_to_render()
%% @see get_custom_text_renderers/0
%% @see add_custom_text_renderer/1

%% @doc Returns the custom text renderer callbacks.
%% @spec () -> [func_info()]
%% @see add_custom_text_renderer/1
%% @see text_to_render()
%% @since #since

-spec get_custom_text_renderers() -> [func_info()].

get_custom_text_renderers() ->
  case ets:lookup(?TABLE, ?CUSTOM_TEXT_RENDERERS) of
    [{_Name, TextRenderers}|_] -> TextRenderers;
    [] -> []
  end.


%% @doc Add a custom text renderer callback.
%% @spec (func_info()) -> no_return()
%% @see get_custom_text_renderer/0
%% @see text_renderer()
%% @since #since

-spec add_custom_text_renderer(func_info()) -> no_return().

add_custom_text_renderer(Fun) ->
  Funs = get_custom_text_renderers(),
  ets:delete(?TABLE, ?CUSTOM_TEXT_RENDERERS),
  ets:insert(?TABLE, {?CUSTOM_TEXT_RENDERERS, [Fun|Funs]}).

